﻿// File operation utilities for UTF-8 encoding support
#include "stdafx.h"
#include "util.h"

#ifndef OS_WIN
#error "Only used on MS-Windows"
#endif

using namespace std;

namespace shared
{
    static const char kEndChar = '\0';
    static const char kFilePathSeparators[] = "\\/";
    static const char kFilePathCurrentDirectory[] = ".";
    static const char kFilePathParentDirectory[] = "..";
    static const char kFilePathExtensionSeparator = '.';

    bool QFilePath::IsFilePathSeparator(const char separator)
    {
        if (separator == kEndChar)
            return false;

        size_t len = sizeof(kFilePathSeparators) / sizeof(char);
        for (size_t i = 0; i < len; i++)
        {
            if (separator == kFilePathSeparators[i])
                return true;
        }

        return false;
    }

    bool QFilePath::FilePathExtension(const string &filepath_in, string &extension_out)
    {
        if (filepath_in.size() == 0)
            return false;
        size_t pos = filepath_in.rfind(kFilePathExtensionSeparator);
        if (pos == string::npos)
            return false;
        extension_out = filepath_in.substr(pos, string::npos);
        return true;
    }

    bool QFilePath::FilePathApartDirectory(const string &filepath_in, string &directory_out)
    {
        size_t index = filepath_in.size() - 1;
        if (index <= 0 || filepath_in.size() == 0)
            return false;
        for (; index != 0; index--)
        {
            if (IsFilePathSeparator(filepath_in[index]))
            {
                if (index == filepath_in.size() - 1)
                    directory_out = filepath_in;
                else
                    directory_out = filepath_in.substr(0, index + 1);
                return true;
            }
        }
        return false;
    }

    // Get the filename from the whole filepath
    bool QFilePath::FilePathApartFileName(const string &filepath_in, string &filename_out)
    {
        size_t index = filepath_in.size() - 1;
        if (index <= 0 || filepath_in.size() == 0)
            return false;
        for (; index != 0; index--)
        {
            if (IsFilePathSeparator(filepath_in[index]))
            {
                if (index == filepath_in.size() - 1)
                    return false;
                filename_out = filepath_in.substr(index + 1, string::npos);
                return true;
            }
        }
        return false;
    }

    template<typename CharType>
    bool ParsePathComponentsT(const CharType *path, const CharType *seperators, std::list<std::basic_string<CharType> > &components)
    {
        components.clear();
        if (path == NULL)
            return false;
        const CharType *prev = NULL;
        const CharType *next = path;
        const CharType *c;
        while (*next)
        {
            prev = next;
            // find the first seperator
            for (;;)
            {
                for (c = seperators; *c && *next != *c; c++);
                if (*c || !*next)
                    break;
                next++;
            }
            components.push_back(std::basic_string<CharType>(prev, next - prev));
            if (*next)
                components.back().push_back(*seperators);
            // skip duplicated seperators
            for (++next;;)
            {
                for (c = seperators; *c && *next != *c; c++);
                if (!*c)
                    break;
                next++;
            }
        }
        return true;
    }

    bool QFilePath::ParsePathComponents(const char *path, std::list<string> &components)
    {
        return ParsePathComponentsT<char>(path, kFilePathSeparators, components);
    }

    bool QFilePath::IsDirectoryComponent(const string &component)
    {
        if (component.empty())
            return false;
        return *component.rbegin() == kFilePathSeparators[0] || *component.rbegin() == kFilePathSeparators[1];
    }

    bool QFilePath::FilePathCompose(const string &directory_in, const string &filename_in, string &filepath_out)
    {
        string directory;
        if (!FilePathApartDirectory(directory_in, directory))
            return false;
        filepath_out = directory + filename_in;
        return true;
    }
} // namespace shared
